package com.kexio.common.utils;

import java.io.File;
import static java.io.File.separator;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;

/**
 * 将项目中的所有 "kexio" 替换为 "kexilo" 的独立执行工具。
 * 执行后会在当前项目根目录旁生成一个新目录：{baseDir}-kexilo
 */
public class KexioRenamer {

    private static final String FROM = "kexio";
    private static final String FROM_CAP = "Kexio";
    private static final String FROM_UP = "KEXIO";

    private static final String TO = "kexilo";
    private static final String TO_CAP = "Kexilo";
    private static final String TO_UP = "KEXILO";

    /**
     * 白名单文件，不进行内容重写，直接拷贝
     */
    private static final Set<String> WHITE_FILE_TYPES = new HashSet<>();
    static {
        // 图片文件
        WHITE_FILE_TYPES.add("gif");
        WHITE_FILE_TYPES.add("jpg");
        WHITE_FILE_TYPES.add("jpeg");
        WHITE_FILE_TYPES.add("svg");
        WHITE_FILE_TYPES.add("png");
        WHITE_FILE_TYPES.add("webp");
        WHITE_FILE_TYPES.add("ico");
        
        // 字体文件
        WHITE_FILE_TYPES.add("eot");
        WHITE_FILE_TYPES.add("woff2");
        WHITE_FILE_TYPES.add("ttf");
        WHITE_FILE_TYPES.add("woff");
        
        // 媒体文件
        WHITE_FILE_TYPES.add("mp4");
        WHITE_FILE_TYPES.add("mp3");
        WHITE_FILE_TYPES.add("wav");
        WHITE_FILE_TYPES.add("avi");
        
        // 压缩包和二进制
        WHITE_FILE_TYPES.add("zip");
        WHITE_FILE_TYPES.add("jar");
        WHITE_FILE_TYPES.add("gz");
    }

    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        String baseDir = getProjectBaseDir();
        
        // 获取项目父目录和项目名
        File baseDirFile = new File(baseDir);
        String parentDir = baseDirFile.getParent();
        String projectName = baseDirFile.getName();
        
        // 在父目录下创建新的项目目录
        String newProjectName = projectName + "-" + TO; // 例如: kexilo_new-kexilo
        String newDir = parentDir + separator + newProjectName;

        System.out.println("[KexioRenamer] 原项目目录 = " + baseDir);
        System.out.println("[KexioRenamer] 父目录     = " + parentDir);
        System.out.println("[KexioRenamer] 项目名     = " + projectName);
        System.out.println("[KexioRenamer] 新项目名   = " + newProjectName);
        System.out.println("[KexioRenamer] 新项目目录 = " + newDir);
        
        if (FileUtil.exist(newDir)) {
            System.err.println("[KexioRenamer] 目标目录已存在：" + newDir + "，请先移除或更换输出目录！");
            return;
        }

        // 列出需要处理的文件
        System.out.println("[KexioRenamer] 开始扫描文件（排除 target/node_modules/.git/.idea/dist 等）...");
        Collection<File> files = listFiles(baseDir);
        System.out.println("[KexioRenamer] 待处理文件数：" + files.size());

        // 处理
        System.out.println("[KexioRenamer] 开始处理文件...");
        int[] counter = {0}; // 计数器
        files.forEach(file -> {
            try {
                // 输出第一个文件的详细信息用于调试
                if (counter[0] == 0) {
                    System.out.println("[KexioRenamer] 第一个文件: " + file.getPath());
                    String newPath = buildNewFilePath(file, baseDir, newDir);
                    System.out.println("[KexioRenamer] 目标路径: " + newPath);
                }
                
                String fileType = getFileType(file);
                if (WHITE_FILE_TYPES.contains(fileType)) {
                    // 白名单：只做路径重写，直接拷贝
                    copyFile(file, baseDir, newDir);
                } else {
                    String content = FileUtil.readString(file, StandardCharsets.UTF_8);
                    String replaced = replaceContent(content);
                    writeFile(file, replaced, baseDir, newDir);
                }
                
                counter[0]++;
                if (counter[0] % 100 == 0) {
                    System.out.println("[KexioRenamer] 已处理 " + counter[0] + " / " + files.size() + " 文件...");
                }
            } catch (Exception e) {
                System.err.println("[KexioRenamer] 处理文件失败: " + file.getPath());
                e.printStackTrace();
            }
        });
        
        System.out.println("[KexioRenamer] 实际处理文件数: " + counter[0]);

        long elapsed = (System.currentTimeMillis() - start) / 1000;
        System.out.println("[KexioRenamer] 完成，耗时 " + elapsed + " 秒，输出目录：" + newDir);
    }

    private static String getProjectBaseDir() {
        String baseDir = System.getProperty("user.dir");
        if (StrUtil.isEmpty(baseDir)) {
            throw new NullPointerException("项目基础路径不存在");
        }
        return baseDir;
    }

    private static Collection<File> listFiles(String projectBaseDir) {
        Collection<File> files = FileUtil.loopFiles(projectBaseDir);
        // 排除构建/工具目录和不需要处理的文件
        return files.stream()
                .filter(file -> {
                    String path = file.getPath();
                    String name = file.getName();
                    
                    // 排除构建目录
                    if (path.contains(separator + "target" + separator)) return false;
                    if (path.contains(separator + "node_modules" + separator)) return false;
                    if (path.contains(separator + "dist" + separator)) return false;
                    
                    // 排除工具目录
                    if (path.contains(separator + ".idea" + separator)) return false;
                    if (path.contains(separator + ".git" + separator)) return false;
                    if (path.contains(separator + ".vscode" + separator)) return false;
                    
                    // 排除日志和存储目录
                    if (path.contains(separator + "logs" + separator)) return false;
                    if (path.contains(separator + "storage" + separator)) return false;
                    
                    // 排除特定文件类型
                    if (name.endsWith(".iml")) return false;
                    if (name.endsWith(".log")) return false;
                    if (name.endsWith(".gz")) return false;
                    if (name.equals("yarn.lock")) return false;
                    if (name.equals("package-lock.json")) return false;
                    if (name.equals("pnpm-lock.yaml")) return false;
                    if (name.endsWith(".tsbuildinfo")) return false;
                    if (name.equals(".DS_Store")) return false;
                    
                    return true;
                })
                .collect(Collectors.toList());
    }

    private static String replaceContent(String content) {
        if (content == null || content.isEmpty()) {
            return content;
        }
        // 优先替换包名前缀，避免二次残留
        return content
                .replace("com." + FROM + ".", "com." + TO + ".")
                .replace(FROM_UP, TO_UP)
                .replace(FROM_CAP, TO_CAP)
                .replace(FROM + "-", TO + "-")
                .replace(FROM + "_", TO + "_")
                .replace(FROM, TO);
    }

    private static void writeFile(File file, String fileContent, String projectBaseDir, String projectBaseDirNew) {
        try {
            String newPath = buildNewFilePath(file, projectBaseDir, projectBaseDirNew);
            // 确保父目录存在
            FileUtil.mkParentDirs(newPath);
            FileUtil.writeUtf8String(fileContent, newPath);
        } catch (Exception e) {
            System.err.println("[KexioRenamer] 写入文件失败: " + file.getPath());
            throw e;
        }
    }

    private static void copyFile(File file, String projectBaseDir, String projectBaseDirNew) {
        try {
            String newPath = buildNewFilePath(file, projectBaseDir, projectBaseDirNew);
            File targetFile = new File(newPath);
            
            // 如果目标文件已存在，先删除
            if (targetFile.exists()) {
                FileUtil.del(targetFile);
            }
            
            FileUtil.mkParentDirs(newPath);
            FileUtil.copyFile(file, targetFile);
        } catch (Exception e) {
            System.err.println("[KexioRenamer] 复制文件失败: " + file.getPath());
            throw e;
        }
    }

    private static String buildNewFilePath(File file, String projectBaseDir, String projectBaseDirNew) {
        // 获取相对于项目根目录的相对路径
        String relativePath = file.getPath().substring(projectBaseDir.length());
        
        // 只对相对路径进行替换，确保 com/kexio -> com/kexilo，以及名称中含 kexio 的文件/目录一并改名
        String renamedRelativePath = relativePath
                .replace("com" + separator + FROM + separator,
                        "com" + separator + TO + separator)
                .replace(FROM, TO)
                .replace(FROM_CAP, TO_CAP)
                .replace(FROM_UP, TO_UP)
                .replaceAll(Pattern.quote(StrUtil.upperFirst(FROM)), Matcher.quoteReplacement(StrUtil.upperFirst(TO)));
        
        // 拼接新的完整路径（不会影响父路径）
        return projectBaseDirNew + renamedRelativePath;
    }

    private static String getFileType(File file) {
        return file.length() > 0 ? FileTypeUtil.getType(file) : "";
    }

}


